Kuasai penanganan kesalahan FastAPI dengan penangan pengecualian kustom. Pelajari cara membuat API yang kuat dengan respons kesalahan yang elegan untuk pengalaman pengguna yang lebih baik.
Penanganan Kesalahan Python FastAPI: Membangun Penangan Pengecualian Kustom yang Kuat
Penanganan kesalahan adalah aspek penting dalam membangun API yang kuat dan andal. Dalam FastAPI Python, Anda dapat memanfaatkan penangan pengecualian kustom untuk menangani kesalahan dengan elegan dan memberikan respons yang informatif kepada klien. Postingan blog ini akan memandu Anda melalui proses pembuatan penangan pengecualian kustom di FastAPI, yang memungkinkan Anda membangun aplikasi yang lebih tangguh dan ramah pengguna.
Mengapa Penangan Pengecualian Kustom?
FastAPI menyediakan dukungan bawaan untuk menangani pengecualian. Namun, hanya mengandalkan respons kesalahan default dapat membuat klien menerima informasi yang samar atau tidak membantu. Penangan pengecualian kustom menawarkan beberapa keuntungan:
- Peningkatan Pengalaman Pengguna: Berikan pesan kesalahan yang jelas dan informatif yang disesuaikan untuk skenario kesalahan tertentu.
- Manajemen Kesalahan Terpusat: Konsolidasikan logika penanganan kesalahan di satu tempat, membuat kode Anda lebih mudah dirawat.
- Respons Kesalahan yang Konsisten: Pastikan respons kesalahan mengikuti format yang konsisten, meningkatkan kegunaan API.
- Peningkatan Keamanan: Mencegah informasi sensitif agar tidak terungkap dalam pesan kesalahan.
- Pencatatan Kustom: Catat informasi kesalahan terperinci untuk tujuan debugging dan pemantauan.
Memahami Penanganan Pengecualian FastAPI
FastAPI menggunakan kombinasi mekanisme penanganan pengecualian bawaan Python dan sistem injeksi dependensinya sendiri untuk mengelola kesalahan. Ketika pengecualian muncul dalam rute atau dependensi, FastAPI mencari penangan pengecualian yang sesuai untuk memprosesnya.
Penangan pengecualian adalah fungsi yang dihiasi dengan @app.exception_handler() yang mengambil dua argumen: jenis pengecualian dan objek permintaan. Penangan bertanggung jawab untuk mengembalikan respons HTTP yang sesuai.
Membuat Pengecualian Kustom
Sebelum mendefinisikan penangan pengecualian kustom, seringkali bermanfaat untuk membuat kelas pengecualian kustom yang mewakili kondisi kesalahan tertentu dalam aplikasi Anda. Ini meningkatkan keterbacaan kode dan mempermudah penanganan berbagai jenis kesalahan.
Misalnya, mari kita katakan Anda sedang membangun API e-commerce dan perlu menangani kasus di mana suatu produk kehabisan stok. Anda dapat mendefinisikan kelas pengecualian kustom bernama OutOfStockError:
class OutOfStockError(Exception):
def __init__(self, product_id: int):
self.product_id = product_id
self.message = f"Produk dengan ID {product_id} kehabisan stok."
Kelas pengecualian kustom ini mewarisi dari kelas Exception dasar dan menyertakan atribut product_id dan pesan kesalahan kustom.
Menerapkan Penangan Pengecualian Kustom
Sekarang, mari kita buat penangan pengecualian kustom untuk OutOfStockError. Penangan ini akan menangkap pengecualian dan mengembalikan respons HTTP 400 (Bad Request) dengan isi JSON yang berisi pesan kesalahan.
from fastapi import FastAPI, Request, HTTPException
from fastapi.responses import JSONResponse
app = FastAPI()
class OutOfStockError(Exception):
def __init__(self, product_id: int):
self.product_id = product_id
self.message = f"Produk dengan ID {product_id} kehabisan stok."
@app.exception_handler(OutOfStockError)
async def out_of_stock_exception_handler(request: Request, exc: OutOfStockError):
return JSONResponse(
status_code=400,
content={"message": exc.message},
)
@app.get("/products/{product_id}")
async def get_product(product_id: int):
# Simulasikan pengecekan stok produk
if product_id == 123:
raise OutOfStockError(product_id=product_id)
return {"product_id": product_id, "name": "Contoh Produk", "price": 29.99}
Dalam contoh ini, dekorator @app.exception_handler(OutOfStockError) mendaftarkan fungsi out_of_stock_exception_handler untuk menangani pengecualian OutOfStockError. Ketika OutOfStockError muncul di rute get_product, penangan pengecualian dipanggil. Penangan kemudian mengembalikan JSONResponse dengan kode status 400 dan isi JSON yang berisi pesan kesalahan.
Menangani Beberapa Jenis Pengecualian
Anda dapat menentukan beberapa penangan pengecualian untuk menangani berbagai jenis pengecualian. Misalnya, Anda mungkin ingin menangani pengecualian ValueError yang terjadi saat mengurai input pengguna.
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
app = FastAPI()
@app.exception_handler(ValueError)
async def value_error_exception_handler(request: Request, exc: ValueError):
return JSONResponse(
status_code=400,
content={"message": str(exc)},
)
@app.get("/items/{item_id}")
async def get_item(item_id: int):
# Simulasikan item_id tidak valid
if item_id < 0:
raise ValueError("ID Item harus berupa bilangan bulat positif.")
return {"item_id": item_id, "name": "Contoh Item"}
Dalam contoh ini, fungsi value_error_exception_handler menangani pengecualian ValueError. Ia mengekstrak pesan kesalahan dari objek pengecualian dan mengembalikannya dalam respons JSON.
Menggunakan HTTPException
FastAPI menyediakan kelas pengecualian bawaan bernama HTTPException yang dapat digunakan untuk memunculkan kesalahan khusus HTTP. Ini dapat berguna untuk menangani skenario kesalahan umum seperti akses tidak sah atau sumber daya tidak ditemukan.
from fastapi import FastAPI, HTTPException
app = FastAPI()
@app.get("/users/{user_id}")
async def get_user(user_id: int):
# Simulasikan pengguna tidak ditemukan
if user_id == 999:
raise HTTPException(status_code=404, detail="Pengguna tidak ditemukan")
return {"user_id": user_id, "name": "Contoh Pengguna"}
Dalam contoh ini, HTTPException muncul dengan kode status 404 (Tidak Ditemukan) dan pesan detail. FastAPI secara otomatis menangani pengecualian HTTPException dan mengembalikan respons JSON dengan kode status dan pesan detail yang ditentukan.
Penangan Pengecualian Global
Anda juga dapat menentukan penangan pengecualian global yang menangkap semua pengecualian yang tidak tertangani. Ini dapat berguna untuk mencatat kesalahan atau mengembalikan pesan kesalahan generik kepada klien.
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
import logging
app = FastAPI()
logger = logging.getLogger(__name__)
@app.exception_handler(Exception)
async def global_exception_handler(request: Request, exc: Exception):
logger.exception(f"Pengecualian yang tidak tertangani: {exc}")
return JSONResponse(
status_code=500,
content={"message": "Kesalahan server internal"},
)
@app.get("/error")
async def trigger_error():
raise ValueError("Ini adalah kesalahan pengujian.")
Dalam contoh ini, fungsi global_exception_handler menangani semua pengecualian yang tidak ditangani oleh penangan pengecualian lainnya. Ia mencatat kesalahan dan mengembalikan respons 500 (Kesalahan Server Internal) dengan pesan kesalahan generik.
Menggunakan Middleware untuk Penanganan Pengecualian
Pendekatan lain untuk penanganan pengecualian adalah dengan menggunakan middleware. Fungsi middleware dieksekusi sebelum dan sesudah setiap permintaan, yang memungkinkan Anda mencegat dan menangani pengecualian pada tingkat yang lebih tinggi. Ini dapat berguna untuk tugas-tugas seperti mencatat permintaan dan respons, atau untuk menerapkan logika otentikasi atau otorisasi kustom.
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
import logging
app = FastAPI()
logger = logging.getLogger(__name__)
@app.middleware("http")
async def exception_middleware(request: Request, call_next):
try:
response = await call_next(request)
except Exception as exc:
logger.exception(f"Pengecualian yang tidak tertangani: {exc}")
return JSONResponse(
status_code=500,
content={"message": "Kesalahan server internal"},
)
return response
@app.get("/error")
async def trigger_error():
raise ValueError("Ini adalah kesalahan pengujian.")
Dalam contoh ini, fungsi exception_middleware membungkus logika pemrosesan permintaan dalam blok try...except. Jika pengecualian muncul selama pemrosesan permintaan, middleware mencatat kesalahan dan mengembalikan respons 500 (Kesalahan Server Internal).
Contoh: Internasionalisasi (i18n) dan Pesan Kesalahan
Saat membangun API untuk audiens global, pertimbangkan untuk menginternasionalkan pesan kesalahan Anda. Ini melibatkan penyediaan pesan kesalahan dalam berbagai bahasa berdasarkan lokal pengguna. Meskipun penerapan i18n penuh berada di luar cakupan artikel ini, berikut adalah contoh sederhana yang menunjukkan konsepnya:
from fastapi import FastAPI, Request, HTTPException
from fastapi.responses import JSONResponse
from typing import Dict
app = FastAPI()
# Kamus terjemahan tiruan (ganti dengan pustaka i18n nyata)
translations: Dict[str, Dict[str, str]] = {
"en": {
"product_not_found": "Produk dengan ID {product_id} tidak ditemukan.",
"invalid_input": "Input tidak valid: {error_message}",
},
"fr": {
"product_not_found": "Produit avec l'ID {product_id} introuvable.",
"invalid_input": "Entrée invalide : {error_message}",
},
"es": {
"product_not_found": "Producto con ID {product_id} no encontrado.",
"invalid_input": "Entrada inválida: {error_message}",
},
"de": {
"product_not_found": "Produkt mit ID {product_id} nicht gefunden.",
"invalid_input": "Ungültige Eingabe: {error_message}",
}
}
def get_translation(locale: str, key: str, **kwargs) -> str:
"""Mengambil terjemahan untuk lokal dan kunci tertentu.
Jika lokal atau kunci tidak ditemukan, mengembalikan pesan default.
"""
if locale in translations and key in translations[locale]:
return translations[locale][key].format(**kwargs)
return f"Terjemahan hilang untuk kunci '{key}' di lokal '{locale}'."
@app.get("/products/{product_id}")
async def get_product(request: Request, product_id: int, locale: str = "en"):
# Simulasikan pencarian produk
if product_id > 100:
message = get_translation(locale, "product_not_found", product_id=product_id)
raise HTTPException(status_code=404, detail=message)
if product_id < 0:
message = get_translation(locale, "invalid_input", error_message="ID Produk harus positif")
raise HTTPException(status_code=400, detail=message)
return {"product_id": product_id, "name": "Contoh Produk"}
Peningkatan utama untuk contoh i18n:
- Parameter Lokal: Rute sekarang menerima parameter kueri
locale, yang memungkinkan klien untuk menentukan bahasa pilihan mereka (default ke "en" untuk Bahasa Inggris). - Kamus Terjemahan: Kamus
translations(tiruan) menyimpan pesan kesalahan untuk berbagai lokal (Bahasa Inggris, Prancis, Spanyol, Jerman dalam kasus ini). Dalam aplikasi nyata, Anda akan menggunakan pustaka i18n khusus. - Fungsi
get_translation: Fungsi pembantu ini mengambil terjemahan yang sesuai berdasarkanlocaledankey. Ini juga mendukung pemformatan string untuk menyisipkan nilai dinamis (sepertiproduct_id). - Pesan Kesalahan Dinamis:
HTTPExceptionsekarang muncul dengan pesandetailyang dihasilkan secara dinamis menggunakan fungsiget_translation.
Ketika klien meminta /products/101?locale=fr, mereka akan menerima pesan kesalahan dalam bahasa Prancis (jika terjemahan tersedia). Saat meminta /products/-1?locale=es, mereka akan menerima pesan kesalahan tentang ID negatif dalam bahasa Spanyol (jika tersedia). Saat meminta /products/200?locale=xx (lokal tanpa terjemahan), mereka akan mendapatkan pesan `Terjemahan hilang`.
Praktik Terbaik untuk Penanganan Kesalahan
Berikut adalah beberapa praktik terbaik yang perlu diingat saat menerapkan penanganan kesalahan di FastAPI:
- Gunakan Pengecualian Kustom: Tentukan kelas pengecualian kustom untuk mewakili kondisi kesalahan tertentu dalam aplikasi Anda.
- Berikan Pesan Kesalahan yang Informatif: Sertakan pesan kesalahan yang jelas dan ringkas yang membantu klien memahami penyebab kesalahan.
- Gunakan Kode Status HTTP yang Sesuai: Kembalikan kode status HTTP yang secara akurat mencerminkan sifat kesalahan. Misalnya, gunakan 400 (Permintaan Buruk) untuk input tidak valid, 404 (Tidak Ditemukan) untuk sumber daya yang hilang, dan 500 (Kesalahan Server Internal) untuk kesalahan yang tidak terduga.
- Hindari Mengungkap Informasi Sensitif: Berhati-hatilah untuk tidak mengungkapkan informasi sensitif seperti kredensial basis data atau kunci API dalam pesan kesalahan.
- Catat Kesalahan: Catat informasi kesalahan terperinci untuk tujuan debugging dan pemantauan. Gunakan pustaka pencatatan seperti modul
loggingbawaan Python. - Pusatkan Logika Penanganan Kesalahan: Konsolidasikan logika penanganan kesalahan di satu tempat, seperti dalam penangan pengecualian kustom atau middleware.
- Uji Penanganan Kesalahan Anda: Tulis pengujian unit untuk memastikan bahwa logika penanganan kesalahan Anda berfungsi dengan benar.
- Pertimbangkan untuk Menggunakan Layanan Pelacakan Kesalahan Khusus: Untuk lingkungan produksi, pertimbangkan untuk menggunakan layanan pelacakan kesalahan khusus seperti Sentry atau Rollbar untuk memantau dan menganalisis kesalahan. Alat-alat ini dapat memberikan wawasan berharga tentang kesehatan aplikasi Anda dan membantu Anda mengidentifikasi dan menyelesaikan masalah dengan cepat.
Kesimpulan
Penangan pengecualian kustom adalah alat yang ampuh untuk membangun API yang kuat dan ramah pengguna di FastAPI. Dengan mendefinisikan kelas dan penangan pengecualian kustom, Anda dapat menangani kesalahan dengan elegan, memberikan respons yang informatif kepada klien, dan meningkatkan keandalan dan pemeliharaan keseluruhan aplikasi Anda. Menggabungkan pengecualian kustom, HTTPExceptions, dan memanfaatkan prinsip i18n jika berlaku, menyiapkan API Anda untuk kesuksesan global.
Ingatlah untuk mempertimbangkan pengalaman pengguna saat merancang strategi penanganan kesalahan Anda. Berikan pesan kesalahan yang jelas dan ringkas yang membantu pengguna memahami masalah dan cara mengatasinya. Penanganan kesalahan yang efektif adalah landasan dalam membangun API berkualitas tinggi yang memenuhi kebutuhan audiens global yang beragam.